home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-1.iso / math / ast51src.zip / IO.C < prev    next >
C/C++ Source or Header  |  1995-12-31  |  24KB  |  714 lines

  1. /*
  2. ** Astrolog (Version 5.10) File: io.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1995 by Walter D. Pullen
  6. ** (Astara@msn.com). Permission is granted to freely use and
  7. ** distribute these routines provided one doesn't sell, restrict, or
  8. ** profit from them in any way. Modification is allowed provided these
  9. ** notices remain with any altered or edited versions of the program.
  10. **
  11. ** The main planetary calculation routines used in this program have
  12. ** been Copyrighted and the core of this program is basically a
  13. ** conversion to C of the routines created by James Neely as listed in
  14. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  15. ** available from Matrix Software. The copyright gives us permission to
  16. ** use the routines for personal use but not to sell them or profit from
  17. ** them in any way.
  18. **
  19. ** The PostScript code within the core graphics routines are programmed
  20. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  21. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  22. **
  23. ** The extended accurate ephemeris databases and formulas are from the
  24. ** calculation routines in the program "Placalc" and are programmed and
  25. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  26. ** (alois@azur.ch). The use of that source code is subject to
  27. ** regulations made by Astrodienst Zurich, and the code is not in the
  28. ** public domain. This copyright notice must not be changed or removed
  29. ** by any user of this program.
  30. **
  31. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  32. ** X Window graphics initially programmed 10/23-29/1991.
  33. ** PostScript graphics initially programmed 11/29-30/1992.
  34. ** Last code change made 12/27/1995.
  35. */
  36.  
  37. #include "astrolog.h"
  38.  
  39.  
  40. /*
  41. ******************************************************************************
  42. ** File IO Routines.
  43. ******************************************************************************
  44. */
  45.  
  46. /* Open the file indicated by the given string and return the file's stream */
  47. /* pointer, or NULL if the file couldn't be found or opened. All parts of   */
  48. /* the program which open files to read call this routine. We look in       */
  49. /* several various locations and directories for the file before giving up. */
  50.  
  51. FILE *FileOpen(szFile, nFileMode)
  52. char *szFile;
  53. int nFileMode;
  54. {
  55.   FILE *file;
  56.   char name[cchSzDef], mode[3];
  57. #ifdef ENVIRON
  58.   char *env;
  59. #endif
  60.  
  61.   /* Some file types we want to open as binary instead of Ascii. */
  62.   sprintf(mode, "r%s", nFileMode == 2 ? "b" : "");
  63.  
  64.   /* First look for the file in the current directory. */
  65.   file = fopen(szFile, mode);
  66.   if (file != NULL)
  67.     return file;
  68.  
  69. #ifdef ENVIRON
  70.   /* Next look for the file in the directory indicated by the version */
  71.   /* specific system environment variable.                            */
  72.   sprintf(name, "%s%s", ENVIRONVER, szVersionCore);
  73.   env = getenv(name);
  74.   if (env && *env) {
  75.     sprintf(name, "%s%c%s", env, chDirSep, szFile);
  76.     file = fopen(name, mode);
  77.     if (file != NULL)
  78.       return file;
  79.   }
  80.  
  81.   /* Next look in the directory in the general environment variable. */
  82.   env = getenv(ENVIRONALL);
  83.   if (env && *env) {
  84.     sprintf(name, "%s%c%s", env, chDirSep, szFile);
  85.     file = fopen(name, mode);
  86.     if (file != NULL)
  87.       return file;
  88.   }
  89.  
  90.   /* Next look in the directory in the version prefix environment variable. */
  91.   env = getenv(ENVIRONVER);
  92.   if (env && *env) {
  93.     sprintf(name, "%s%c%s", env, chDirSep, szFile);
  94.     file = fopen(name, mode);
  95.     if (file != NULL)
  96.       return file;
  97.   }
  98. #endif
  99.  
  100.   /* Finally look in one of several directories specified at compile time. */
  101.   sprintf(name, "%s%c%s", nFileMode == 0 ? DEFAULT_DIR :
  102.     (nFileMode == 1 ? CHART_DIR : EPHE_DIR), chDirSep, szFile);
  103.   file = fopen(name, mode);
  104.   if (file == NULL && nFileMode == 1) {
  105.     /* If the file was never found, print an error (unless we were looking */
  106.     /* for a certain file type, e.g. the optional astrolog.dat file).      */
  107.     sprintf(name, "File '%s' not found.", szFile);
  108.     PrintError(name);
  109.   }
  110.   return file;
  111. }
  112.  
  113.  
  114. /* This is Astrolog's generic file processing routine, which handles chart */
  115. /* info files, position files, and config files. Given a file name or a    */
  116. /* file handle, run through each line as a series of command switches.     */
  117.  
  118. bool FProcessSwitchFile(szFile, file)
  119. char *szFile;
  120. FILE *file;
  121. {
  122.   char szLine[cchSzMax], *argv[MAXSWITCHES], ch;
  123.   int argc, i;
  124.  
  125.   if (file == NULL)
  126.     file = FileOpen(szFile, 0);
  127.   if (file == NULL)
  128.     return fFalse;
  129.  
  130.   /* All files have to begin with the -@ switch file type identifier. */
  131.   ch = getc(file); ungetc(ch, file);
  132.   if (ch != '@') {
  133.     sprintf(szLine,
  134.       "The command file '%s' is not in any valid format (character %d).",
  135.       szFile, (int)ch);
  136.     PrintWarning(szLine);
  137.     return fFalse;
  138.   }
  139.  
  140.   loop {
  141.     while (!feof(file) && (ch = getc(file)) < ' ')
  142.       ;
  143.     if (feof(file))
  144.       break;
  145.     for (szLine[0] = ch, i = 1; i < cchSzMax && !feof(file) &&
  146.       (szLine[i] = getc(file)) >= ' '; i++)
  147.       ;
  148.     szLine[i] = chNull;
  149.     argc = NParseCommandLine(szLine, argv);
  150.     if (!FProcessSwitches(argc, argv))
  151.       return fFalse;
  152.   }
  153.   return fTrue;
  154. }
  155.  
  156.  
  157. /* Take the current chart information, and write it out to the file   */
  158. /* as indicated by the -o switch. This is only executed at the end of */
  159. /* program execution if the -o switch is in effect.                   */
  160.  
  161. bool FOutputData()
  162. {
  163.   char sz[cchSzDef];
  164.   FILE *file;
  165.   int i, j;
  166.   real rT;
  167.  
  168.   if (us.fNoWrite)
  169.     return fFalse;
  170.   file = fopen(is.szFileOut, "w");  /* Create and open the file for output. */
  171.   if (file == NULL) {
  172.     sprintf(sz, "File %s can not be created.", is.szFileOut);
  173.     PrintError(sz);
  174.     return fFalse;
  175.   }
  176.   if (!us.fWritePos) {
  177.  
  178.     /* Write the chart information to the file. */
  179.  
  180.     if (Mon < 1) {
  181.       fclose(file);
  182.       PrintError("Can't output chart with no time/space to file.");
  183.       return fFalse;
  184.     }
  185.     if (us.fWriteOld) {
  186.       fprintf(file, "%d\n%d\n%d\n%.2f\n%.2f\n%.2f\n%.2f\n",
  187.         Mon, Day, Yea, Tim, Zon-Dst, Lon, Lat);
  188.     } else {
  189.       fprintf(file, "@0102  ; %s chart info.\n", szAppName);
  190.       i = us.fAnsi;
  191.       us.fAnsi = fFalse;
  192.       fprintf(file, "%cqb %c%c%c %d %d %s %s %s %s\n", chSwitch, chMon3(Mon),
  193.         Day, Yea, SzTim(Tim), Dst == 0.0 ? "ST" : (Dst == 1.0 ? "DT" :
  194.         SzZone(Dst)), SzZone(-Zon), SzLocation(Lon, Lat));
  195.       fprintf(file, "%czi \"%s\" \"%s\"\n", chSwitch, ciMain.nam, ciMain.loc);
  196.       us.fAnsi = i;
  197.     }
  198.   } else {
  199.  
  200.     /* However, if the -o0 switch is in effect, then write the actual */
  201.     /* positions of the planets and houses to the file instead.       */
  202.  
  203.     if (us.fWriteOld) {
  204.       for (i = 1; i <= oNorm; i++) {
  205.         j = (int)planet[i];
  206.         fprintf(file, "%c%c%c: %2d %2d %10.7f\n", chObj3(i),
  207.           j%30, j/30+1, RFract(planet[i])*60.0);              /* Position */
  208.         rT = planetalt[i];
  209.         fprintf(file, "[%c]: %3d %12.8f\n",                   /* Altitude */
  210.           ret[i] >= 0.0 ? 'D' : chRet, (int)(RSgn(rT)*
  211.           RFloor(RAbs(rT))), (rT-(real)(int)rT)*60.0);     /* Retrograde? */
  212.         if (i == oNod)
  213.           i = oFor-1;
  214.         else if (i == oFor)
  215.           i = oMC -1;
  216.         else if (i == oMC)
  217.           i = oAsc-1;
  218.         else if (i == oAsc)
  219.           i = oVtx-1;
  220.         else if (i == oVtx)    /* Skip minor cusps to write uranians  */
  221.           i = us.fUranian ? uranLo-1 : cObj;
  222.       }
  223.       for (i = 1; i <= cSign/2; i++) {   /* Write first six cusp positions */
  224.         j = (int)house[i];
  225.         fprintf(file, "H_%c: %2d %2d %10.7f\n",
  226.           'a'+i-1, j%30, j/30+1, RFract(house[i])*60.0);
  227.       }
  228.  
  229.     } else {
  230.       fprintf(file, "@0203  ; %s chart positions.\n", szAppName);
  231.       for (i = 1; i <= cObj; i++) if (!ignore[i] || FCusp(i)) {
  232.         fprintf(file, "%cYF ", chSwitch);
  233.         if (i <= oNorm)
  234.           fprintf(file, "%c%c%c", chObj3(i));
  235.         else
  236.           fprintf(file, "%3d", i);
  237.         rT = FBetween(i, cuspLo-1+4, cuspLo-1+9) ?
  238.           house[i-(cuspLo-1)] : planet[i];
  239.         j = (int)rT;
  240.         fprintf(file, ":%3d %c%c%c%13.9f,%4d%13.9f,",
  241.           j%30, chSig3(j/30+1), RFract(rT)*60.0,
  242.           (int)planetalt[i], RFract(RAbs(planetalt[i]))*60.0);
  243.         rT = i > oNorm ? 999.0 : (i == oMoo && !us.fPlacalc ? 0.0026 :
  244.           RSqr(spacex[i]*spacex[i]+spacey[i]*spacey[i]+spacez[i]*spacez[i]));
  245.         fprintf(file, "%14.9f%14.9f\n", DFromR(ret[i]), rT);
  246.       }
  247.     }
  248.   }
  249.  
  250.   /* Now write any extra strings that were on the command line after the -o */
  251.   /* specification but before the next switch, to the file as comments.     */
  252.  
  253.   for (i = 1; i < is.cszComment; i++) {
  254.     is.rgszComment++;
  255.     fprintf(file, "%s%s\n", us.fWriteOld ? "" : "; ", is.rgszComment[1]);
  256.   }
  257.   fclose(file);
  258.   return fTrue;
  259. }
  260.  
  261.  
  262. /*
  263. ******************************************************************************
  264. ** User Input Routines.
  265. ******************************************************************************
  266. */
  267.  
  268. /* Given a string, return an index number corresponding to what the string */
  269. /* indicates, based on a given parsing mode. In most cases this is mainly  */
  270. /* looking up a string in the appropriate array and returning the index.   */
  271.  
  272. int NParseSz(szEntry, pm)
  273. char *szEntry;
  274. int pm;
  275. {
  276.   char szLocal[cchSzMax], *sz, ch0, ch1, ch2;
  277.   int cch, n, i;
  278.  
  279.   /* First strip off any leading or trailing spaces. */
  280.   for (cch = 0; szLocal[cch] = szEntry[cch]; cch++)
  281.     ;
  282.   while (cch && szLocal[cch-1] <= ' ')
  283.     szLocal[--cch] = chNull;
  284.   for (sz = szLocal; *sz && *sz <= ' '; sz++, cch--)
  285.     ;
  286.  
  287.   if (cch >= 3) {
  288.     ch0 = ChCap(sz[0]); ch1 = ChUncap(sz[1]); ch2 = ChUncap(sz[2]);
  289.     switch (pm) {
  290.     /* Parse months, e.g. "February" or "Feb" -> 2 for February. */
  291.     case pmMon:
  292.       for (i = 1; i <= cSign; i++) {
  293.         if (ch0 == szMonth[i][0] && ch1 == szMonth[i][1] &&
  294.           ch2 == szMonth[i][2])
  295.           return i;
  296.       }
  297.       break;
  298.     /* Parse planets, e.g. "Jupiter" or "Jup" -> 6 for Jupiter. */
  299.     case pmObject:
  300.       for (i = 1; i <= cObj; i++) {
  301.         if (ch0 == szObjName[i][0] && ch1 == szObjName[i][1] &&
  302.           ch2 == szObjName[i][2])
  303.           return i;
  304.       }
  305.       if (ch0 == 'L' && ch1 == 'i' && ch2 == 'l')
  306.         return oLil;
  307.       if (ch0 == 'S' && ch1 == '.' && ch2 == 'n')
  308.         return oSou;
  309.       break;
  310.     /* Parse aspects, e.g. "Conjunct" or "Con" -> 1 for the Conjunction. */
  311.     case pmAspect:
  312.       for (i = 1; i <= cAspect; i++) {
  313.         if (ch0 == szAspectAbbrev[i][0] &&
  314.           ch1 == ChUncap(szAspectAbbrev[i][1]) &&
  315.           ch2 == szAspectAbbrev[i][2])
  316.           return i;
  317.       }
  318.       break;
  319.     /* Parse house systems, e.g. "Koch" or "Koc" -> 1 for Koch houses. */
  320.     case pmSystem:
  321.       for (i = 1; i <= cSystem; i++) {
  322.         if (ch0 == szSystem[i][0] && ch1 == szSystem[i][1] &&
  323.           ch2 == szSystem[i][2])
  324.           return i;
  325.       }
  326.     /* Parse zodiac signs, e.g. "Scorpio" or "Sco" -> 8 for Scorpio. */
  327.     case pmSign:
  328.       for (i = 1; i <= cSign; i++) {
  329.         if (ch0 == szSignName[i][0] && ch1 == szSignName[i][1] &&
  330.           ch2 == szSignName[i][2])
  331.           return i;
  332.       }
  333.     /* Parse colors, e.g. "White" or "Whi" -> 15 for White. */
  334.     case pmColor:
  335.       for (i = 0; i < 16 ; i++) {
  336.         if (ch0 == szColor[i][0] && ch1 == szColor[i][1] &&
  337.           ch2 == ChUncap(szColor[i][2]))
  338.           return i;
  339.       }
  340.     }
  341.   }
  342.   n = atoi(sz);
  343.  
  344.   if (pm == pmYea) {
  345.     /* For years, process any "BC" (or "B.C.", "b.c", and variations) and   */
  346.     /* convert an example such as "5BC" to -4. For negative years, note the */
  347.     /* difference of one, as 1AD was preceeded by 1BC, with no year zero.   */
  348.     i = Max(cch-1, 0);
  349.     if (i && sz[i] == '.')
  350.       i--;
  351.     if (i && ChCap(sz[i]) == 'C')
  352.       i--;
  353.     if (i && sz[i] == '.')
  354.       i--;
  355.     if (i && ChCap(sz[i]) == 'B')
  356.       n = 1 - n;
  357.   }
  358.   return n;
  359. }
  360.  
  361.  
  362. /* Given a string, return a floating point number corresponding to what the  */
  363. /* string indicates, based on a given parsing mode, like above for integers. */
  364.  
  365. real RParseSz(szEntry, pm)
  366. char *szEntry;
  367. int pm;
  368. {
  369.   char szLocal[cchSzMax], *sz, *pch, ch;
  370.   int cch, i, f = fFalse;
  371.   real r;
  372.  
  373.   /* First strip off any leading or trailing spaces. */
  374.   for (cch = 0; szLocal[cch] = szEntry[cch]; cch++)
  375.     ;
  376.   while (cch && szLocal[cch-1] <= ' ')
  377.     szLocal[--cch] = chNull;
  378.   for (sz = szLocal; *sz && *sz <= ' '; sz++, cch--);
  379.     ;
  380.   /* Capitalize all letters and make colons be periods to be like numbers. */
  381.   for (pch = sz; *pch; pch++) {
  382.     ch = *pch;
  383.     if (ch == ':')
  384.       ch = '.';
  385.     else
  386.       ch = ChCap(ch);
  387.     *pch = ch;
  388.   }
  389.   ch = sz[0];
  390.  
  391.   if (pm == pmTim) {
  392.     /* For times, process "Noon" and "Midnight" (or just "N" and "M"). */
  393.     if (ch == 'N')
  394.       return 12.0;
  395.     else if (ch == 'M')
  396.       return 0.0;
  397.   } else if (pm == pmDst) {
  398.     /* For the Daylight time flag, "Daylight", "Yes", and "True" (or just */
  399.     /* their first characters) are all indications to be ahead one hour.  */
  400.     if (ch == 'D' || ch == 'Y' || ch == 'T')
  401.       return 1.0;
  402.     /* "Standard", "No", and "False" mean the normal zero offset. */
  403.     else if (ch == 'S' || ch == 'N' || ch == 'F')
  404.       return 0.0;
  405.   } else if (pm == pmZon) {
  406.     /* For time zones, see if the abbrev is in a table, e.g. "EST" -> 5. */
  407.     for (i = 0; i < cZone; i++)
  408.       if (NCompareSz(sz, szZon[i]) == 0)
  409.         return rZon[i];
  410.   } else if (pm == pmLon || pm == pmLat) {
  411.     /* For locations, negate the value for an "E" or "S" in the middle    */
  412.     /* somewhere (e.g. "105E30" or "27:40S") for eastern/southern values. */
  413.     for (i = 0; i < cch; i++) {
  414.       ch = sz[i];
  415.       if (FCapCh(ch)) {
  416.         if (ch == 'E' || ch == 'S')
  417.           f = fTrue;
  418.         sz[i] = '.';
  419.         i = cch;
  420.       }
  421.     }
  422.     ch = sz[0];
  423.   }
  424.  
  425.   /* Anything still at this point should be in a numeric format. */
  426.   if (!FNumCh(ch) && ch != '+' && ch != '-' && ch != '.')
  427.     return rLarge;
  428.   r = (f ? -1.0 : 1.0) * atof(sz);
  429.  
  430.   if (pm == pmTim) {
  431.     /* Backtrack over any time suffix, e.g. "AM", "p.m." and variations. */
  432.     i = Max(cch-1, 0);
  433.     if (i && sz[i] == '.')
  434.       i--;
  435.     if (i && sz[i] == 'M')
  436.       i--;
  437.     if (i && sz[i] == '.')
  438.       i--;
  439.     if (i) {
  440.       ch = sz[i];
  441.       if (ch == 'A')                   /* Adjust value appropriately */
  442.         r = r >= 12.0 ? r-12.0 : r;    /* if AM or PM suffix.        */
  443.       else if (ch == 'P')
  444.         r = r >= 12.0 ? r : r+12.0;
  445.     }
  446.   }
  447.   return r;
  448. }
  449.  
  450.  
  451. /* Stop and wait for the user to enter a line of text given a prompt to */
  452. /* display and a string buffer to fill with it.                         */
  453.  
  454. void InputString(szPrompt, sz)
  455. char *szPrompt, *sz;
  456. {
  457.   FILE *file;
  458.   int cch;
  459.  
  460.   file = S; S = stdout;
  461.   PrintSz(szPrompt);
  462.   AnsiColor(kYellow);
  463.   PrintSz(" > ");
  464.   AnsiColor(kDefault);
  465.   if (fgets(sz, cchSzMax, stdin) == NULL)  /* Pressing control-D terminates */
  466.     Terminate(tcForce);                    /* the program on some machines. */
  467.   cch = CchSz(sz);
  468.   while (cch > 0 && sz[cch-1] < ' ')
  469.     cch--;
  470.   sz[cch] = chNull;
  471.   S = file;
  472.   is.cchCol = 0;
  473. }
  474.  
  475.  
  476. /* Prompt the user for a floating point value, parsing as appropriate, and */
  477. /* make sure it conforms to the specified bounds before returning it.      */
  478.  
  479. int NInputRange(szPrompt, low, high, pm)
  480. char *szPrompt;
  481. int low, high;
  482. int pm;
  483. {
  484.   char szLine[cchSzDef];
  485.   int n;
  486.  
  487.   loop {
  488.     InputString(szPrompt, szLine);
  489.     n = NParseSz(szLine, pm);
  490.     if (FBetween(n, low, high))
  491.       return n;
  492.     sprintf(szLine, "Value %d out of range from %d to %d.", n, low, high);
  493.     PrintWarning(szLine);
  494.   }
  495. }
  496.  
  497.  
  498. /* This is identical to above except it takes/returns floating point values. */
  499.  
  500. real RInputRange(szPrompt, low, high, pm)
  501. char *szPrompt;
  502. real low, high;
  503. int pm;
  504. {
  505.   char szLine[cchSzDef];
  506.   real r;
  507.  
  508.   loop {
  509.     InputString(szPrompt, szLine);
  510.     r = RParseSz(szLine, pm);
  511.     if (FBetween(r, low, high))
  512.       return r;
  513.     sprintf(szLine, "Value %.0f out of range from %.0f to %.0f.",
  514.       r, low, high);
  515.     PrintWarning(szLine);
  516.   }
  517. }
  518.  
  519.  
  520. /* This important procedure gets all the parameters defining the chart that  */
  521. /* will be worked with later. Given a "filename", it gets from it all the    */
  522. /* pertinent chart information. This is more than just reading from a file - */
  523. /* the procedure also takes care of the cases of prompting the user for the  */
  524. /* information and using the time functions to determine the date now - the  */
  525. /* program considers these cases "virtual" files. Furthermore, when reading  */
  526. /* from a real file, we have to check if it was written in the -o0 format.   */
  527.  
  528. bool FInputData(szFile)
  529. char *szFile;
  530. {
  531.   FILE *file;
  532.   char sz[cchSzDef], ch;
  533.   int i, fT;
  534.   real k, l, m;
  535.  
  536.   /* If we are to read from the virtual file "nul" that means to leave the */
  537.   /* chart information alone with whatever settings it may have already.   */
  538.  
  539.   if (NCompareSz(szFile, szNulCore) == 0) {
  540.     is.fHaveInfo = fTrue;
  541.     return fTrue;
  542.   }
  543.  
  544.   /* If we are to read from the virtual file "set" then that means use a   */
  545.   /* particular set of chart information generated earlier in the program. */
  546.  
  547.   if (NCompareSz(szFile, szSetCore) == 0) {
  548.     is.fHaveInfo = fTrue;
  549.     ciCore = ciSave;
  550.     return fTrue;
  551.   }
  552.  
  553. #ifdef TIME
  554.   /* If we are to read from the file "now" then that means use the time */
  555.   /* functions to calculate the present date and time.                  */
  556.  
  557.   if (NCompareSz(szFile, szNowCore) == 0) {
  558.     is.fHaveInfo = fTrue;
  559.     SS = us.dstDef; ZZ = us.zonDef; OO = us.lonDef; AA = us.latDef;
  560.     GetTimeNow(&MM, &DD, &YY, &TT, ZZ-SS);
  561.     ciCore.nam = ciCore.loc = "";
  562.     return fTrue;
  563.   }
  564. #endif
  565.  
  566. #ifndef WIN
  567.   /* If we are to read from the file "tty" then that means prompt the user */
  568.   /* for all the chart information.                                        */
  569.  
  570.   if (NCompareSz(szFile, szTtyCore) == 0) {
  571.     file = S; S = stdout;
  572.     if (!us.fNoSwitches) {
  573.       /* Temporarily disable an internal redirection of output to a file  */
  574.       /* because we always want user headers and prompts to be displayed. */
  575.  
  576.       AnsiColor(kWhite);
  577.       sprintf(sz, "** %s version %s ", szAppName, szVersionCore); PrintSz(sz);
  578.       sprintf(sz, "(See '%cHc' switch for copyrights and credits.) **\n",
  579.         chSwitch); PrintSz(sz);
  580.       AnsiColor(kDefault);
  581.       sprintf(sz, "   Invoke as '%s %cH' for list of command line options.\n",
  582.         ProcessProgname(is.szProgName), chSwitch); PrintSz(sz);
  583.     }
  584.  
  585.     MM = NInputRange("Enter month for chart (e.g. '8' 'Aug')",
  586.       1, 12, pmMon);
  587.     DD = NInputRange("Enter day   for chart (e.g. '1' '31') ",
  588.       1, DayInMonth(MM, 0), pmDay);
  589.     YY = NInputRange("Enter year  for chart (e.g. '1995')   ",
  590.       -5000, 5000, pmYea);
  591.     if (FBetween(YY, 0, 99)) {
  592.       sprintf(sz,
  593.         "Assuming first century A.D. is really meant instead of %d.",
  594.         1900 + YY);
  595.       PrintWarning(sz);
  596.     }
  597.     TT = RInputRange("Enter time  for chart (e.g. '18:30' '6:30pm')  ",
  598.       -2.0, 24.0, pmTim);
  599.     SS = us.fWriteOld ? 0.0 :
  600.       RInputRange("Enter if Daylight time in effect (e.g. 'y' '1')",
  601.       -24.0, 24.0, pmDst);
  602.     ZZ = RInputRange("Enter time zone (e.g. '5' 'ET' for Eastern)    ",
  603.       -24.0, 24.0, pmZon);
  604.     if ((int)(RFract(ZZ) * 100.0 + rRound) == 50) {
  605.       PrintWarning(
  606.         "Assuming unusual zone of 50 minutes after the hour instead of 30.");
  607.     }
  608.     OO = RInputRange("Enter Longitude of place (e.g. '122W20')",
  609.       -rDegHalf, rDegHalf, pmLon);
  610.     AA = RInputRange("Enter Latitude  of place (e.g. '47N36') ",
  611.       -rDegQuad, rDegQuad, pmLat);
  612.     if (!us.fWriteOld) {
  613.       InputString("Enter name or title for chart ", sz);
  614.       ciCore.nam = SzPersist(sz);
  615.       InputString("Enter name of city or location", sz);
  616.       ciCore.loc = SzPersist(sz);
  617.     }
  618.     PrintL();
  619.     is.cchRow = 0;
  620.     S = file;
  621.     return fTrue;
  622.   }
  623. #endif /* WIN */
  624.  
  625.   /* Now that the special cases are taken care of, we can assume we are */
  626.   /* to read from a real file.                                          */
  627.  
  628.   file = FileOpen(szFile, 1);
  629.   if (file == NULL)
  630.     return fFalse;
  631.   is.fHaveInfo = fTrue;
  632.   ch = getc(file); ungetc(ch, file);
  633.  
  634.   /* Read the chart parameters from a standard command switch file. */
  635.  
  636.   if (ch == '@') {
  637.     fT = is.fSzPersist; is.fSzPersist = fFalse;
  638.     if (!FProcessSwitchFile(szFile, file))
  639.       return fFalse;
  640.     is.fSzPersist = fT;
  641.  
  642.   /* Read the chart info from an older style -o list of seven numbers. */
  643.  
  644.   } else if (FNumCh(ch)) {
  645.     SS = 0.0;
  646.     fscanf(file, "%d%d%d", &MM, &DD, &YY);
  647.     fscanf(file, "%lf%lf%lf%lf", &TT, &ZZ, &OO, &AA);
  648.     if (!FValidMon(MM) || !FValidDay(DD, MM, YY) || !FValidYea(YY) ||
  649.       !FValidTim(TT) || !FValidZon(ZZ) || !FValidLon(OO) || !FValidLat(AA)) {
  650.       PrintWarning("Values in old style chart info file are out of range.");
  651.       return fFalse;
  652.     }
  653.  
  654.   /* Read the actual chart positions from a file produced with the -o0. */
  655.  
  656.   } else if (ch == 'S') {
  657.     MM = -1;
  658.  
  659.     /* Hack: A negative month value means the chart parameters are invalid, */
  660.     /* hence -o0 is in effect and we can assume the chart positions are     */
  661.     /* already in memory so we don't have to calculate them later.          */
  662.  
  663.     for (i = 1; i <= oNorm; i++) {
  664.       fscanf(file, "%s%lf%lf%lf", sz, &k, &l, &m);
  665.       planet[i] = Mod((l-1.0)*30.0+k+m/60.0);
  666.       fscanf(file, "%s%lf%lf", sz, &k, &l);
  667.       if ((m = k+l/60.0) > rDegHalf)
  668.         m = rDegMax - m;
  669.       planetalt[i] = m;
  670.       ret[i] = RFromD(sz[1] == 'D' ? 1.0 : -1.0);
  671.  
  672.       /* -o0 files from versions 3.05 and before don't have the uranians in  */
  673.       /* them. Be prepared to skip over them in old files for compatibility. */
  674.  
  675.       if (i == oVtx) {
  676.         while (getc(file) >= ' ')
  677.           ;
  678.         if ((ch = getc(file)) != 'H')
  679.           i = cuspHi;
  680.         else
  681.           i = cObj;
  682.       }
  683.       if (i == oNod)
  684.         i = oFor-1;
  685.       else if (i == oFor)
  686.         i = oLil-1;
  687.       else if (i == oLil)
  688.         i = oEP -1;
  689.       else if (i == oEP)
  690.         i = oVtx-1;
  691.     }
  692.     for (i = 1; i <= cSign/2; i++) {
  693.       fscanf(file, "%s%lf%lf%lf", sz, &k, &l, &m);
  694.       house[i+6] = Mod((house[i] = Mod((l-1.0)*30.0+k+m/60.0))+rDegHalf);
  695.     }
  696.     for (i = 1; i <= cSign; i++)
  697.       planet[cuspLo-1+i] = house[i];
  698.     planet[oMC] = planet[oLil]; planet[oNad] = Mod(planet[oMC]  + rDegHalf);
  699.     planet[oAsc] = planet[oEP]; planet[oDes] = Mod(planet[oAsc] + rDegHalf);
  700.     planet[oSou] = Mod(planet[oNod] + rDegHalf); ret[oSou] = ret[oNod];
  701.  
  702.   } else {
  703.     sprintf(sz,
  704.       "The chart info file is not in any valid format (character %d).",
  705.       (int)ch);
  706.     PrintWarning(sz);
  707.     return fFalse;
  708.   }
  709.   fclose(file);
  710.   return fTrue;
  711. }
  712.  
  713. /* io.c */
  714.